#pragma once

#include <string>
#include <list>
#include "..\common\common.h"
#include "params.h"

using namespace std;
using namespace AI9;

namespace ArmyStateNS {

class BaseState 
{
public:
	BaseState(AI9::GeneralType name) : m_name(name) { } 
	virtual string get_type() = 0;
	virtual void execute() = 0;
	virtual void cancel() {}

	static void enter_state(GeneralType name, BaseState *from_state, BaseState *state);
	static void require_action(GeneralType fellow, BaseState *required_state);
protected:
	AI9::GeneralType m_name;
};

class IdleState : public BaseState
{
public:
	IdleState(AI9::GeneralType name) : BaseState(name) {  } 
	virtual string get_type() { return "IdleState"; } 
	virtual void execute();
};

class InitState : public BaseState
{
public:
	InitState(AI9::GeneralType name) : BaseState(name) {  } 
	virtual string get_type() { return "InitState"; } 
	virtual void execute();

public:
	static bool initialized;
};

class OccupyingState : public BaseState
{
public:
	static std::map<GeneralType, Position> target_map;
	static bool find_target(GeneralType general, Position &target);
	static bool city_assigned(Position p);
	static void assign(GeneralType general, Position p);
	static void remove(GeneralType general);

};

class FastOccupyingState : public BaseState
{
public:
	FastOccupyingState(AI9::GeneralType name) : BaseState(name) 
	{
		m_target = Position(-1, -1);
	}
 
	FastOccupyingState(AI9::GeneralType name, Position target) : BaseState(name) 
	{
		 
		m_target = target;
	}
 
	virtual string get_type() { return "FastOccupyingState"; } 
	virtual void execute();

	Position m_target;
};

class ManageState : public BaseState
{
public:
	ManageState(AI9::GeneralType name) : BaseState(name) {   m_target = Position(-1, -1); } 
	ManageState(AI9::GeneralType name, Position target) : BaseState(name) {  m_target = target; } 
	virtual string get_type() { return "ManageState"; } 
	virtual void execute();

	static bool get_manager_offer(Position &center);
	static void assign_manager(Position center, GeneralType name);
	static void refresh_managing_state();
	static void remove_manager(GeneralType name);

	typedef std::list<std::pair<GeneralType, Position> > managing_map_t;
	static managing_map_t managing_map;

public:
	Position m_target;
};

class BattleState: public BaseState
{
public:
	BattleState(AI9::GeneralType name) : BaseState(name) {   } 
	virtual string get_type() { return "BattleState"; } 
	virtual void execute();
};

class WithdrawState: public BaseState
{
public:
	WithdrawState(AI9::GeneralType name) : BaseState(name) {} 
	virtual string get_type() { return "WithdrawState"; } 
	virtual void execute();

	bool find_safe_move();
	bool find_strong_fellow();
};

class DefensiveBattleState: public BaseState
{
public:
	DefensiveBattleState(AI9::GeneralType name, Position target) : BaseState(name) {  m_target = target; } 
	virtual string get_type() { return "DefensiveBattleState"; } 
	virtual void execute();
	
	void find_safe_place_around();

public:
	Position m_target;
};

class OffensiveBattleState : public BaseState
{
public:
	OffensiveBattleState(AI9::GeneralType name) : BaseState(name) {  m_target = Position(-1, -1); } 
	OffensiveBattleState(AI9::GeneralType name, Position target) : BaseState(name) {  m_target = target; } 
	virtual string get_type() { return "OffensiveBattleState"; } 
	virtual void execute();

	void find_target();

public:
	Position m_target;

	struct PositionIndex
	{
		PositionIndex(Position p) { hash = p.x < 0 ? -1 : p.x * 1000 + p.y; }
		Position to_position() { return hash < 0 ? Position(-1, -1) : Position(hash / 1000, hash % 1000); }

		bool operator<(const PositionIndex &x) const { return hash < x.hash; }

		int hash;
	};

	static map<PositionIndex, int> city_hardness;
};

class TemporalState : public BaseState
{
public:
	TemporalState(AI9::GeneralType name, BaseState *parent) : BaseState(name) {  m_parent = parent; } 
	virtual string get_type() { return "TemporalState"; } 
	virtual void execute() = 0;
	
	void resume_previous_state();
	void abandon_and_enter(BaseState *next_state);

public:
	BaseState *m_parent;
};

class TemporalAttackingState : public TemporalState
{
public:
	TemporalAttackingState(AI9::GeneralType name, BaseState *parent, Position target_city) : TemporalState(name, parent) 
	{ 
		m_type = ATTACKING_CITY;
		target_city_pos = target_city;
		executed = false;
	} 

	TemporalAttackingState(AI9::GeneralType name, BaseState *parent, AI9::GeneralType target_general) : TemporalState(name, parent) 
	{ 
		m_type = ATTACKING_GENERAL;
		target_general_name = target_general;
		executed = false;
	} 

	virtual string get_type() { return "TemporalAttackingState"; } 
	virtual void execute();

public:
	bool executed;
	Position target_city_pos;
	AI9::GeneralType target_general_name;
	enum attacking_state_t { ATTACKING_GENERAL, ATTACKING_CITY };
	attacking_state_t m_type;
};

}